<?php
/*
Copyright (c) 2007, Martin Maly

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

/**
 * uniqID
 * 
 * uniqID is a library to provide simple way for generating and checking
 * unique IDs for using in web forms. Its goals are:
 * - to generate unique ID for web form (send in HIDDEN field)
 * - to check given ID for its validity
 * - to assure once generated ID will never be used again
 * This library does not generate global unique IDs!
 * 
 */             

//cache path - the place where emitted IDs lives ;)
//This path must be accessible from PHP and the script must have rights
//for writing to this directory 
define('UNIQ_PATH','./tmp/',1);

//UniqID time-to-live value in seconds 
define('UNIQ_TTL',3600,1); //one hour

//here are two lines with uniqID encryption data as generated by uniqgen.php Please generate them
//by opening uniqgen.php in your browser and copy generated lines AS IS into this place: 
//---
define('UNIQ_SALT','7VkbUD|sGNjIf|ZLK2P0|c8hRYO|WAeiqX|aMl1wv|Cd9Jop|yrzuSn|gtx4Q6|B3FTHm|5E',1);
define('UNIQ_SWAPS','9,0,22,12,3,19,8,1,5,16,17,18,10,24,15,2,6,7,25,21,14,23,11,13,4,20',1);
//---

//Some helper functions

/**
 * genuniq()
 * Generates unique ID as string XXXXXX-YYYYYY-ZZZZZZ,
 * where XXXXXX is actual timestamp, YYYYYY is microtime
 * and ZZZZZZ is random generated number
 * 
 */     
function genuniq(){ 
    list($usec, $sec) = explode(" ",microtime()); 
    $uniq=$sec.'-'.substr($usec,2).'-'.rand(100000,999999);  
    return $uniq;
} 

/**
 * saltuniq(), saltuniq2()
 * Generates forward and backward converting arrays for uniqID encryption/decryption
 * 
 */
    
function saltuniq(){
 $salt=explode('|',UNIQ_SALT);
 return $salt;
}
function saltuniq2(){
 $salt=explode('|',UNIQ_SALT);
 $a=array();
 $i=0;
 foreach ($salt as $s){
  for ($j=0;$j<strlen($s);$j++) $a[ord($s[$j])]=$i;
  $i++;
  if($i==10) $i='-';
 }
 return $a;
}


//swaps $a-th and $b-th chars in $s string
function swap_helper($s,$a,$b){
 $x=$s[$a];
 $s[$a]=$s[$b];
 $s[$b]=$x;
 return $s;
}

/**
 * swap_forward(), swap_backward()
 * mixes and unmixes strings according to UNIQ_SWAP information
 * 
 */   
function swap_forward($s){
 $swp=explode(',',UNIQ_SWAPS);
 for ($i=0;$i<26;$i+=2){
  $s=swap_helper($s,$swp[$i],$swp[$i+1]);
 }
 for ($i=1;$i<24;$i+=2){
  $s=swap_helper($s,$swp[$i],$swp[$i+1]);
 }
return $s;
}
function swap_backward($s){
 $swp=explode(',',UNIQ_SWAPS);
 for ($i=1;$i<24;$i+=2){
  $s=swap_helper($s,$swp[$i],$swp[$i+1]);
 }
 for ($i=0;$i<26;$i+=2){
  $s=swap_helper($s,$swp[$i],$swp[$i+1]);
 }
return $s;
}

/**
 * encodeuniq(), decodeuniq()
 * obfuscates and de-obfuscates generated IDs to provide
 * its higher safety
 * 
 */     

function encodeuniq($uniq){
 $s='';
 $salt=saltuniq();
 for($i=0;$i<strlen($uniq);$i++){
  $c=$uniq[$i];
  if ($c=='-')$c=10; else $c=intval($c);
  $sc=$salt[$c];
  $sr=rand(0,strlen($sc)-1);
  $s.=$sc[$sr];
 }
 return swap_forward($s);
}

function decodeuniq($uniq){
 $s='';
 $salt=saltuniq2();
 $uniq=swap_backward($uniq);
 for($i=0;$i<strlen($uniq);$i++){
  $c=$uniq[$i];
  $s.=$salt[ord($c)];
 }
 return $s;
}


//MAIN FUNCTIONS

/**
 * getuniq()
 * Main function providing generating uniqID
 * Generates ID and noticed that this ID was given
 * with information of client IP given ID generated for.   
 * Only two first numbers are saved from client's IP
 * 
 */   

function getuniq(){
    $ip=explode('.',$_SERVER['REMOTE_ADDR']);
    $uniq=genuniq();
    file_put_contents(UNIQ_PATH.$uniq.'.uniq',md5($ip[0].'.'.$ip[1])); 
    return encodeuniq($uniq);
}

/**
 * checkuniq()
 * Function checks if given uniqID was released,
 * if IP matches to the value previously saved with this ID
 * and marks this ID as "used" to avoiding multiple using of one ID
 * Returns 1 if given ID was assigned, unused and valid,
 * returns 0 if given ID was misused or invalid or used by somebody
 * with different IP
 */     

function checkuniq($uniq){
 $uniq=decodeuniq($uniq);
 if (!file_exists(UNIQ_PATH.$uniq.'.uniq')) return 0;
 if (filemtime(UNIQ_PATH.$uniq.'.uniq')<(time()-UNIQ_TTL)) 
  {unlink(UNIQ_PATH.$uniq.'.uniq');return 0;} //TTL check, thanks to Jakub Vrana
 $ip=explode('.',$_SERVER['REMOTE_ADDR']);
 $get=file_get_contents(UNIQ_PATH.$uniq.'.uniq'); 
 if ($get!=md5($ip[0].'.'.$ip[1])) return 0;
 return unlink(UNIQ_PATH.$uniq.'.uniq');
}

/**
 * purgeuniq()
 * Purges generated and unused IDs after its TTL period is gone
 * You must provide periodical calling of this functions to purge
 * unused uniqIDs, ideally with some kind of CRON  
 * 
 */
     
function purgeuniq(){

 $uniqdir=UNIQ_PATH;
 $limit=time()-UNIQ_TTL;
 $limitlen=strlen($limit);
 $handle=opendir(UNIQ_PATH);
 while (false!==($file = readdir($handle))) {
    if (strpos($file,'.uniq')) {
        if (intval(substr($file,0,$limitlen))<$limit) unlink(UNIQ_PATH.$file);
    }
    
 }
 closedir($handle);
}


//--------------------------------------------------------------------------------
//=============       HERE IS THE END OF THE UNIQID CODE     ===================== 
//--------------------------------------------------------------------------------

?>